/* Copyright (C) 2007-2010 Open Information Security Foundation
 *
 * You can copy, redistribute or modify this Program under the terms of
 * the GNU General Public License version 2 as published by the Free
 * Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * version 2 along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 */

/**
 * \ingroup decode
 *
 * @{
 */


/**
 * \file
 *
 * \author Prabhakaran Kasinathan <kasinthan@ismb.it>
 *
 * Decode IEEE 802.15.4
 */

#include "suricata-common.h"
#include "decode.h"
#include "decode-ieee802154.h"
#include "decode-events.h"

#include "util-unittest.h"
#include "util-debug.h"



void DecodeIeee802154(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq)
{
    SCPerfCounterIncr(dtv->counter_ieee802154, tv->sc_perf_pca);

    

     if (len < IEEE802154_HEADER_LEN | len > IEEE802154_MAX_FRAME_LEN) {
        ENGINE_SET_EVENT(p,IEEE802154_PKT_TOO_SMALL);
	SCLogInfo("IEEE802154 Wrong Header Length"); // a event detection event should be defined .. to be done later.
	return;     
	}
  
   p->ieeeh = (Ieee802154Hdr *)pkt;
    
/* old code which uses the Anoop Method. But not useful for now. 
    //SCLogInfo("Length of the Packet %d",len);
    // SCLogInfo("p %p pkt %p Len: %d",p,pkt,len); 
    uint8_t dstpan;
    uint8_t dstadd;
    uint8_t srcadd;
    dstpan = ((p->ieeeh->ieee802154_dstpan1)+(p->ieeeh->ieee802154_dstpan2));
    dstadd = ((p->ieeeh->ieee802154_dstadd1)+(p->ieeeh->ieee802154_dstadd2));
    srcadd = ((p->ieeeh->ieee802154_srcadd1)+(p->ieeeh->ieee802154_srcadd2));
  
*/    
	
    uint8_t dstpan;
    uint8_t dstadd;
    uint8_t srcadd;
    dstpan = (p->ieeeh->ieee802154_dstpan);
    dstadd = (p->ieeeh->ieee802154_dstadd);	

    p->ieeeh = (Ieee802154Hdr *)pkt;



    if ((IEEE802154_GET_FRAME_TYPE(p)) == NULL) {
	SCLogInfo("Ieee802154 Header is null");
        return;
   
       }

   printf("\n Length  %d ieee FCF: %x | ieee seq %x | DstPan  %04x | Dstadd %04X | SrcAdd %04x ",len,(p->ieeeh->ieee802154_fcf),(p->ieeeh->ieee802154_seq),IEEE802154_GET_DSTPAN(p),dstadd,srcadd);


    

   printf("\n Address Type : Dst Add FCF: %04x | Src Add FCF: %04x |", IEEE802154_GET_DSTADD(p),IEEE802154_GET_SRCADD(p));
   //uint8_t ft;
   //uint8_t fa_s;
   //uint8_t fa_d;
 
    //SCLogInfo("One before **");
    //ft = ((p->ieeeh->ieee802154_fcf) & IEEE802154_FCF_TYPE_MASK);   
    //ft = GET_IEEE802154_FRAME_TYPE(p);
    //fa_s = ((p->ieeeh->ieee802154_fcf) & IEEE802154_FCF_SADDR_MASK);
    //fa_d = ((p->ieeeh->ieee802154_fcf) & IEEE802154_FCF_DADDR_MASK);
    

    
switch (IEEE802154_GET_FRAME_TYPE(p)) {
          case IEEE802154_ACK:
            SCLogInfo("Ack Found *****");
            
            break;
        case IEEE802154_BEACON:	
	    SCLogInfo("Beacon Found *****");            
	    
            break;
        case IEEE802154_COMMAND:
            SCLogInfo("Command Found *****");  
            
            break;
        case IEEE802154_DATA:
	    SCLogInfo("IEEE802154 Data Found..");
            
            //printf("\n Length  %d ieee FCF: %x | ieee seq %d | DstPan  %04x | Dstadd %04X | SrcAdd %04x ",
		//          len,(p->ieeeh->ieee802154_fcf),(p->ieeeh->ieee802154_seq),dstpan,dstadd,srcadd);
	     
	
            if ((IEEE802154_GET_DSTADD(p) == IEEE802154_FCF_ADDR_SHORT) && (IEEE802154_GET_SRCADD(p) == IEEE802154_FCF_ADDR_SHORT)) {

	    DecodeSixlowpan(tv, dtv, p, pkt + 9,len - 9, pq); 
 	    }

	    else if ((IEEE802154_GET_DSTADD(p) == IEEE802154_FCF_ADDR_SHORT) && (IEEE802154_GET_SRCADD(p) == IEEE802154_FCF_ADDR_EXT)) {
            printf("short long\n");
	    DecodeSixlowpan(tv, dtv, p, pkt + 15,len - 15, pq); 
 	    }

	    else if ((IEEE802154_GET_DSTADD(p) == IEEE802154_FCF_ADDR_EXT) && (IEEE802154_GET_SRCADD(p) == IEEE802154_FCF_ADDR_SHORT)) {

	    DecodeSixlowpan(tv, dtv, p, pkt + 15,len - 15, pq); 
 	    }

	    else {
	    printf("Two Long Packets ");
	    DecodeSixlowpan(tv, dtv, p, pkt + 21,len - 21, pq);
	    printf("left 6lowpan decoder");
	    }


            break;
        default:
            SCLogInfo("p %p pkt %p ieee802154 type %04x not supported", p,
                       pkt, ntohs(p->ieeeh->ieee802154_fcf));
    }


    return;
 
 
}

#ifdef UNITTESTS
/** DecodeIeee802154test01
 *  \brief Valid Ieee802154 packet
 *  \retval 0 Expected test value
 */
static int DecodeIeee802154Test01 (void)   {

	/* yet to be written */
    /* ICMP packet wrapped in PPPOE */
    uint8_t raw_ieee802154[] = {
        0x61, 0x88, 0xd9, 0x22, 0x00, 0x01, 0x00, 0x64,
	0x00, 0xe0, 0x8a, 0xa5, 0x20, 0x10, 0x90, 0x01,
	0x90, 0x01, 0x90, 0x01, 0x90, 0x01, 0x90, 0x01,
	0x47, 0x7a, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
        0xab, 0xcd };

    Packet *p = SCMalloc(SIZE_OF_PACKET);
    if (p == NULL)
    return 0;
    ThreadVars tv;
    DecodeThreadVars dtv;

    memset(&dtv, 0, sizeof(DecodeThreadVars));
    memset(&tv,  0, sizeof(ThreadVars));
    memset(p, 0, SIZE_OF_PACKET);
    p->pkt = (uint8_t *)(p + 1);

    DecodeIeee802154(&tv, &dtv, p, raw_ieee802154, sizeof(raw_ieee802154), NULL);

    SCFree(p);
    return 0;
}
#endif /* UNITTESTS */


/**
 * \brief Registers Ieee802154 unit tests
 * \todo More Ieee802154 tests
 */
void DecodeIeee802154RegisterTests(void) {
#ifdef UNITTESTS
    UtRegisterTest("DecodeIeee802154Test01", DecodeIeee802154Test01, 1);
#endif /* UNITTESTS */
}
/**
 * @}
 */
